package com.auth.sdk.transmit;

import com.alibaba.fastjson.JSON;

import com.auth.sdk.Headers;
import com.auth.sdk.LoginInfo;
import com.common.global.R;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * Token filter
 *
 * @description: 过滤器，生成登录态数据 并校验请求头。token.filter.ignore 忽略接口
 * @author: cyj
 * @date 2021 -12-23 10:38:29
 */
@Order(Integer.MIN_VALUE)
@WebFilter(filterName = "tokenFilter", urlPatterns = "/*")
@Slf4j
public class TokenFilter extends OncePerRequestFilter implements LonginContextTransmitAbstract<HttpServletRequest> {

    @Value("${token.filter.ignore:}")
    private String ignoreUrls;

    @Value("${spring.profiles.active:prod}")
    private String active;

    @Value("${server.servlet.context-path:}")
    private String contextPath;

    @PostConstruct
    public void init() {
        log.info("！！TokenFilter已加载，默认拦截所有url, 可以配置 token.filter.ignore 属性进行忽略, 以';'隔开, 支持通配符！！");
    }

    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) {

        contextTransmit(servletRequest, () -> {
            if (this.doFilter(servletRequest, servletResponse)) {
                try {
                    filterChain.doFilter(servletRequest, servletResponse);
                } catch (IOException | ServletException e) {
                    e.printStackTrace();
                    writeError(servletResponse, e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
                }
            }
        });


    }

    private void writeError(HttpServletResponse servletResponse, String message, HttpStatus httpStatus) {

        servletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = servletResponse.getWriter()) {
            writer.print(JSON.toJSONString(R.error(String.valueOf(httpStatus.value()), message, null)));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    private boolean doFilter(HttpServletRequest httpRequest, HttpServletResponse httpServletResponse) {
        String requestUrl = httpRequest.getRequestURI();
        String id = LoginContextHolder.getLoginId();

        log.info("请求开始，用户: {}, 请求地址：{}", id, requestUrl);
        AntPathMatcher matcher = new AntPathMatcher();
        for (String ignoreUrl : this.getIgnoreUrls()) {
            if (matcher.match(ignoreUrl, requestUrl)) {
                return true;
            }
        }

        if (StringUtils.isEmpty(LoginContextHolder.getLoginName()) || StringUtils.isEmpty(LoginContextHolder.getLoginId())) {
            log.info("非法操作用户！");
            writeError(httpServletResponse, "非法操作用户！", HttpStatus.UNAUTHORIZED);
            return false;
        }
        return true;
    }

    private List<String> getIgnoreUrls() {
        List<String> splitIgnoreUrls = Arrays.asList(ignoreUrls.split(";")).stream().collect(Collectors.toList());
        splitIgnoreUrls.add(contextPath + "/static/");
        // 解决swagger无法访问
        splitIgnoreUrls.add(contextPath + "/swagger-ui.html");
        splitIgnoreUrls.add(contextPath + "/resources/");
        splitIgnoreUrls.add(contextPath + "/swagger-resources/**");
        splitIgnoreUrls.add(contextPath + "/v2/api-docs");
        // 解决swagger的js文件无法访问
        splitIgnoreUrls.add(contextPath + "/webjars/**");
        splitIgnoreUrls.add(contextPath + "/resources/webjars/");
        splitIgnoreUrls.add(contextPath + "/doc.html");
        splitIgnoreUrls.add(contextPath + "/auth/csrf");
        splitIgnoreUrls.add(contextPath + "/favicon.ico");
        splitIgnoreUrls.add(contextPath + "/actuator/**");
        splitIgnoreUrls.add(contextPath + "/*/");

        // 或者这些
//         - /debug/**
//         - /**/open/**
//         - /v2/api-docs
//         - /**/swagger-ui.html/**
//         - /**/swagger-resources/**
//         - /**/*.html
//                - /**/*.css
//                - /**/*.js
        return splitIgnoreUrls;
    }

    @Override
    public void destroy() {

    }

    @Override
    public void setLonginContext(HttpServletRequest httpRequest) {
        String id = httpRequest.getHeader(Headers.USER_ID);
        String name = httpRequest.getHeader(Headers.USER_NAME);
        String roles = httpRequest.getHeader(Headers.ROLES);
        String auths = httpRequest.getHeader(Headers.AUTHS);
        LoginContextHolder.setLoginInfo(new LoginInfo(id, name, JSON.parseArray(roles), JSON.parseArray(auths)));
    }

    @Override
    public void removeLonginContext() {
        LoginContextHolder.removeLoginInfo();
    }
}
